home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
commands
/
rmdir.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
5KB
|
219 lines
/* rmdir - remove a directory Author: Adri Koppes
/* (modified by Paul Polderman)
* (modified by Bjarne Steinsbo) Fixed "rmdir ../anything"
* Modified style to standard Minix
* Added some comments.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <limits.h>
#include <string.h>
int error = 0;
main(argc, argv)
register int argc;
register char **argv;
{
if (argc < 2) {
prints("Usage: rmdir dir ...\n");
exit(1);
}
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
while (--argc) remove(*++argv);
if (error) exit(1);
}
remove(dirname)
char *dirname;
{
struct direct d; /* buffer for reading directory */
struct stat s, cwd; /* buffers for `stat' call */
int fd = 0;
int sl = 0;
int n;
char dots[PATH_MAX]; /* scratch buffer for dirname */
register char *p;
/* Is the path name too long ? Check once and for all. */
if (strlen(dirname) > PATH_MAX - 3) { /* Need to append `/..' */
stderr2("path name too long : ", dirname);
std_err("\n");
error++;
return;
}
/* Does the file exist ? */
if (stat(dirname, &s)) {
stderr2(dirname, " doesn't exist\n");
error++;
return;
}
/* Is it a directory ? */
if ((s.st_mode & S_IFMT) != S_IFDIR) {
stderr2(dirname, " not a directory\n");
error++;
return;
}
/* If path ends in /., fix it (e.g., /usr/ast/. ==> /usr/ast). */
while (1) {
n = strlen(dirname);
if (n > 2 && dirname[n-2] == '/' && dirname[n-1] == '.')
dirname[n-2] = 0;
else
break;
}
/* Are we trying to remove "." or ".." ? */
if (p = strrchr(dirname, '/'))
p++;
else
p = dirname;
if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
stderr2(dirname, " will not remove \".\" or \"..\"\n");
error++;
return;
}
/* Write permission in parent directory ? */
strcpy(dots, dirname);
while (dirname[fd])
if (dirname[fd++] == '/') sl = fd;
dots[sl] = '\0';
if (*dots == '\0') strcpy(dots, ".");
if (access(dots, 2)) {
stderr2(dirname, " no permission\n");
error++;
return;
}
/* Are we trying to remove current directory ? */
stat(".", &cwd);
if ((s.st_ino == cwd.st_ino) && (s.st_dev == cwd.st_dev)) {
std_err("rmdir: can't remove current directory\n");
error++;
return;
}
/* Is it possible to open the directory ? */
if ((fd = open(dirname, O_RDONLY)) < 0) {
stderr2("can't read ", dirname);
std_err("\n");
error++;
return;
}
/* Is the directory empty ? (except "." and "..") */
while(read(fd, (char *) &d, sizeof(struct direct)) == sizeof(struct direct)){
if (d.d_ino != 0) {
if (strcmp(d.d_name, ".") && strcmp(d.d_name, "..")) {
stderr2(dirname, " not empty\n");
close(fd);
error++;
return;
}
}
}
close(fd);
/* Will the path name be invalidated when dirname/. or dirname/.. is
* unlinked ? In that case, fix the path-name ! */
strcpy(dots, dirname);
patch_path(dots);
/* OK, let's do the rmdir. */
if (rmdir(dots) != 0) {
stderr2("can't remove ", dots);
std_err("\n");
error++;
return;
}
}
stderr2(s1, s2)
char *s1, *s2;
{
std_err("rmdir: ");
std_err(s1);
std_err(s2);
}
/* With s pointing to the first char in the next part of the pathname,
* check if this part is empty (/), dot (./) or dotdot (../)
*/
#define IS_EMPTY(s) (*(s) == '/')
#define IS_DOT(s) (*(s) == '.' && *((s)+1) == '/')
#define IS_DOTDOT(s) (*(s) == '.' && *((s)+1) == '.' && *((s)+2) == '/')
patch_path(dir)
char *dir;
{
/* Check if the path name will be invalidated when `dirname/..' and
* `dirname/.' is later unlinked. Return a (possibly) patched path.
* Do this by cleaning the path up, i.e. removing unnecessary parts
* of the path. `anypath/anything/../' , `anypath/./' and `anypath//'
* are all considered equal to `anypath/' . This assumption will break
* when symbolic links are (are they ?) introduced. Don't remove those
* `../' parts that are essential to the path name.
*/
register char *p;
char *last;
int level = 0;
if (*dir == '/') /* absolute ? */
last = dir + 1;
else
last = dir;
p = last;
while (*p != '\0') { /* clean up the path name */
if (IS_EMPTY(p)) { /* reduce `//' to `/' */
StrCpy(p, p + 1);
continue;
}
if (IS_DOT(p)) { /* reduce `/./' to `/' */
StrCpy(p, p + 2);
continue;
}
if (IS_DOTDOT(p)) { /* reduce `/anything/../' to `/' */
if (level > 0) {/* is it possible to reduce? */
--level;
StrCpy(last, p + 3);
p = last;
last -= 2;
while (*last != '/' && last > dir) --last;
if (*last == '/') last++;
} else
last = p += 3;
continue;
}
last = p;
level++;
while (*p != '\0' && *p++ != '/'); /* get next part of path
* name */
}
}
StrCpy(s, t)
register char *s, *t;
{
/* Overlapping copies are implemetation-dependent in strcpy, so we'll
* use our own version.
*/
while (*s++ = *t++) /* do nothing */
;
}